# -*- coding: iso-8859-2 -*-

from authorshipanalyzer.file import ResourceReader
from authorshipanalyzer.utils import normalizeVector
from authorshipanalyzer.utils import sortDictionaryByValue
from authorshipanalyzer.utils import getKey

class VSMAnalyzer:
    '''
    Vector Space Model analyzer
    '''
    
    def __init__(self, categories):
        '''
        @param categories: dict<category_name, dict<word, freq>>
        '''
        self.categories = categories
        for key in self.categories.keys():
            normalizeVector(categories[key])

    def categorize(self, messageWords):
        '''
        @return: closest category
        '''
        return self.choose(self.analyze(messageWords))

    def analyze(self, messageWords):
        '''
        Main method which categorize message using
        Vector Space Model and cosinus comparison
        @param message
        '''        
        resultsMap = {}
        normalizeVector(messageWords)
        for categoryName in self.categories.keys():
            cosinus = self.cosinus(self.categories[categoryName], messageWords)
            resultsMap[categoryName] = cosinus
        return resultsMap
        
    def cosinus(self, dict1, dict2):
        '''
        Count cosinus
        @precondition: vectors are normalized
        '''            
        cosinus = 0.0
        for word, freq in dict2.items():
            #due to the problem with equality of keys in
            #has_key method when key contains polish signs 
            word = getKey(dict1, word)      
            if word != None:
                if dict1[word] > 0:
                    cosinus += dict1[word] * freq
        return cosinus
    
    def choose(self, resultMap):
        '''
        Choose the closest result
        base on the cosinus of vectors.
        @param categoryMap: map<name, consiuns>
        @return: the most apropriete result or
        unknown
        '''
        resultMap = sortDictionaryByValue(resultMap)
        
        #Cannot be!
        if (len(resultMap) < 1):
            raise Exception
        
        #If not similar to anything
        if resultMap[0][1] == 0:
            return "unknown"
        
        #If there is only one candidate
        if resultMap[1][1] == 0:
            return resultMap[0][0]
        
        #If there is a high similarity
        if resultMap[0][1] >= 0.025:
           return resultMap[0][0]
       
        #If first category is much more similar then the
        # second one
        if resultMap[0][1] > 1.5 * resultMap[1][1]:
            return resultMap[0][0] 
        
        #All other cases
        return "unknown"